﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Input;
using Microsoft.Win32;
using System.Windows;
using System.Xml;
using SHomeWorkshop.LunarConcept.Controls;
using SHomeWorkshop.LunarConcept.Widgets;
using SHomeWorkshop.LunarConcept.ModifingManager;
using SHomeWorkshop.LunarConcept.Widgets.Interfaces;

namespace SHomeWorkshop.LunarConcept.Commands
{
    /// <summary>
    /// 创建时间：2012年3月24日
    /// 创建者：  杨震宇
    /// 
    /// 主要用途：将选定部件格式化为表格命令。
    /// ★★说明：关于自定义命令的实现，可参考“NewDocument”类的备注。
    /// </summary>
    public static class FoamatAsTableCommand
    {
        #region 构造方法=====================================================================================================

        /// <summary>
        /// ★②，修改静态构造方法名。
        /// </summary>
        static FoamatAsTableCommand()//类型构造器
        {
            //★③，修改两个字符串参数名。★④以及第三个参数的类型名。
            routedUICmd = new RoutedUICommand(
                "FoamatAsTableCommand",
                "FoamatAsTableCommand",
                typeof(FoamatAsTableCommand),//创建RoutedUICommand对象
                null);

            //如果需要挂接快捷键，请参考下面这段代码：
            //routedUICmd = new RoutedUICommand(
            //    "SaveDocumentCommand",
            //    "SaveDocumentCommand",
            //    typeof(SaveDocumentCommand),//创建RoutedUICommand对象
            //    new InputGestureCollection() 
            //    { 
            //        //★⑤，修改此处三个参数，以便挂接快捷键。
            //        new KeyGesture(Key.S,ModifierKeys.Control,"Ctrl+S")
            //    });

            cmdBinding.Command = routedUICmd;
            cmdBinding.CanExecute += new CanExecuteRoutedEventHandler(cmdBinding_CanExecute);
            cmdBinding.Executed += new ExecutedRoutedEventHandler(cmdBinding_Executed);
        }

        #endregion

        #region 字段与属性===================================================================================================

        private static CommandBinding cmdBinding = new CommandBinding();
        /// <summary>
        /// 用在主窗口CommandBindings集合中的命令绑定。
        /// 
        /// 它的Command是RoutedUICommand。
        /// ——因此，RoutedUICommand是否可以运行将由CmdBinding的CanExecute事件决定。
        /// ——而且，RoutedUICommand的执行也是通过CmdBinding的Execute事件来进行的。
        /// </summary>
        public static CommandBinding CmdBinding
        {
            get { return cmdBinding; }
        }

        private static RoutedUICommand routedUICmd;
        /// <summary>
        /// [只读静态属性]表示在WPF系统中注册的一个RoutedUICommand。
        /// ——必须和CommandBinding配合才能使用。
        ///     CommandBinding要添加到主窗口的CommandBindings集合中；
        ///     RoutedUICommand则要向WPF系统注册。
        ///     
        /// ★说明：使用静态属性是因为这样在Xaml代码中比较便于绑定。
        /// </summary>
        public static RoutedUICommand RoutedUICmd
        {
            get { return routedUICmd; }
        }

        #endregion

        #region 方法=========================================================================================================

        static void cmdBinding_CanExecute(object sender, CanExecuteRoutedEventArgs e)
        {
            //★⑧，修改此方法的实现。

            //考虑到性能问题，全部取消此判断。反正执行时会判断。
            //if (Globals.MainWindow == null) { e.CanExecute = false; return; }
            //EditorManager manager = Globals.MainWindow.EditorManager;
            //if (manager == null) { e.CanExecute = false; return; }
            //PageEditor mainPe = manager.GetMainSelectedPageEditor();
            //if (mainPe == null) { e.CanExecute = false; return; }
            //int selCount = mainPe.GetSelectedWidgetsCount();
            //if (selCount < 2) { e.CanExecute = false; return; }

            e.CanExecute = true;
        }

        static void cmdBinding_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            //★⑦，修改此方法的实现。

            string result = Execute();
            if (result != string.Empty)
            {
                MessageBox.Show("　　未能按表格样式排列。错误消息如下：\r\n" + result,
                    Globals.AppName, MessageBoxButton.OK, MessageBoxImage.Warning);
                return;
            }
        }

        /// <summary>
        /// [公开静态方法]即使此命令处于禁用状态，也可以通过代码调用此方法来执行特定任务！！！
        /// 
        /// 当被绑定的命令被调用（触发）时，会引发cmdBinding_Executed事件。
        /// 在cmdBinding_Executed事件处理器方法中已添加了调用Execute()方法的代码。
        /// 
        /// ——因此，触发命令，就相当于调用此方法！！！
        /// </summary>
        public static string Execute(double padding = 10, bool formatFixedRectangles = true)
        {
            if (Globals.MainWindow == null) return "　　未找到Globals.MainWindow。";
            EditorManager manager = Globals.MainWindow.EditorManager;
            if (manager == null) return "　　未找到页面管理器。";
            PageEditor pageEditor = manager.GetMainSelectedPageEditor();
            if (pageEditor == null) return "　　当前没有选定任何页面。";

            List<Widgets.Widget> selectedWidgets = pageEditor.GetSelectedWidgetsList(true);
            if (selectedWidgets.Count < 2) return "　　至少选定两个部件（连接线不算）。";

            ModifingInfo info = new ModifingInfo() { ModifingDescription = "尝试按表格样式排列部件" };
            manager.GetSelectedPageEditorStatus(info);
            manager.GetSelectedWidgetStatus_Old(info);
            manager.GetSelectedWidgetStatus_New(info);

            ModifingItem<Action, ModifingInfo> mi = new ModifingItem<Action, ModifingInfo>(info);

            //先取出最小、大横坐标与最小、大纵坐标
            double minX = pageEditor.EditArea.Right;
            double minY = pageEditor.EditArea.Bottom;
            double maxX = 0, maxY = 0;
            foreach (Widget w in selectedWidgets)
            {
                Point pt = w.TopLeft;
                if (pt.X < minX) minX = pt.X;
                if (pt.Y < minY) minY = pt.Y;
                if (pt.X > maxX) maxX = pt.X;
                if (pt.Y > maxY) maxY = pt.Y;
            }

            if (minX >= maxX && minY >= maxY) return "　　所选定的各部件位置关系太乱，无法继续尝试格式化。";

            //取出所有行、列
            List<List<Widget>> rows = new List<List<Widget>>();
            List<List<Widget>> columns = new List<List<Widget>>();

            #region 取出所有行、列
            double x = minX;
            while (x < maxX + 20)
            {
                double right = x + 20;

                List<Widget> row = new List<Widget>();

                foreach (Widget w in selectedWidgets)
                {
                    Point pt = w.TopLeft;
                    if (pt.X >= x && pt.X < right)
                    {
                        row.Add(w);
                    }
                }

                if (row.Count > 0)
                {
                    rows.Add(row);
                }

                x = right;
            }

            double y = minY;
            while (y < maxY + 20)
            {
                double bottom = y + 20;

                List<Widget> column = new List<Widget>();

                foreach (Widget w in selectedWidgets)
                {
                    Point pt = w.TopLeft;
                    if (pt.Y >= y && pt.Y < bottom)
                    {
                        column.Add(w);
                    }
                }

                if (column.Count > 0)
                {
                    columns.Add(column);
                }

                y = bottom;
            }
            #endregion

            #region 验证行、列中单元格数目是否相等。
            int columnsCount = columns.Count;
            int rowsCount = rows.Count;

            bool columnEqual = true;
            bool rowEqual = true;
            foreach (List<Widget> row in rows)
            {
                if (columnsCount != row.Count) columnEqual = false;
            }

            foreach (List<Widget> column in columns)
            {
                if (rowsCount != column.Count) rowEqual = false;
            }

            if (columnEqual == false || rowEqual == false)
                return
@"　　选定的各部件【左上角】排列得不够整齐，或者行、列中部件数目不一致，无法近似地分析出适用的二维表格结构。

　　请保证它们的左上角排列得尽可能整齐。

　　★这个功能主要是用模拟一张二维表格时，对齐各部件的【右下角】的，而且不支持【合并单元格】这样的复杂情况。";

            #endregion
            
            //先自适应矩形的底边（如有必要）。
            if (formatFixedRectangles)
            {
                foreach (Widget w in selectedWidgets)
                {
                    Widgets.RectangleWidget rw = w as Widgets.RectangleWidget;
                    if (rw == null) continue;

                    if (rw.FixTextWidth)
                    {
                        Widgets.RectangleWidget.ResetRectangleWidgetHeight(mi, rw);
                    }
                    else
                    {
                        Widgets.RectangleWidget.ResetRectangleSize(mi, rw);
                    }
                }
            }

            double yOffset = minY;
            foreach (List<Widget> column in columns)
            {
                double maxHight = 0;
                foreach (Widget w in column)
                {
                    Widgets.RectangleWidget rw = w as Widgets.RectangleWidget;
                    if (rw != null && rw.FixTextWidth)
                    {
                        Widgets.RectangleWidget.ResetRectangleWidgetHeight(mi, rw);
                    }

                    Point pt = w.TopLeft;
                    if (pt.Y != yOffset)
                    {
                        w.MoveTopSiderTo(mi, yOffset);
                    }

                    double height = w.RealRect.Height;
                    if (height > maxHight)
                    {
                        maxHight = height;
                    }
                }

                foreach (Widget w in column)
                {
                    Widgets.RectangleWidget rw = w as Widgets.RectangleWidget;//只有RectangleWidget才允许调整尺寸。
                    if (rw == null) continue;
                    if (rw.RealRect.Height == maxHight) continue;

                    if (rw.StartPoint.Y > rw.EndPoint.Y)
                    {
                        Point newPt = new Point(rw.StartPoint.X, rw.EndPoint.Y + maxHight);
                        Action act = new Action(pageEditor.Id, rw.Id, rw.GetType().Name, XmlTags.StartPointTag,
                            rw.StartPoint.ToString(), newPt.ToString());
                        rw.StartPoint = newPt;
                        mi.AddAction(act);
                    }
                    else
                    {
                        Point newPt = new Point(rw.EndPoint.X, rw.StartPoint.Y + maxHight);
                        Action act = new Action(pageEditor.Id, rw.Id, rw.GetType().Name, XmlTags.EndPointTag,
                            rw.EndPoint.ToString(), newPt.ToString());
                        rw.EndPoint = newPt;
                        mi.AddAction(act);
                    }
                }

                yOffset += maxHight + padding;//最大高度+间距！！！
            }


            double xOffset = minX;
            foreach (List<Widget> row in rows)
            {
                double maxWidth = 0;
                foreach (Widget w in row)
                {
                    Point pt = w.TopLeft;
                    if (pt.X != xOffset)
                    {
                        w.MoveLeftSiderTo(mi, xOffset);
                    }

                    double width = w.RealRect.Width;
                    if (width > maxWidth)
                    {
                        maxWidth = width;
                    }
                }

                foreach (Widget w in row)
                {
                    Widgets.RectangleWidget rw = w as Widgets.RectangleWidget;//只有RectangleWidget才允许调整尺寸。
                    if (rw == null) continue;
                    if (rw.RealRect.Width == maxWidth) continue;

                    if (rw.StartPoint.X > rw.EndPoint.X)
                    {
                        Point newPt = new Point(rw.EndPoint.X + maxWidth, rw.StartPoint.Y);
                        Action act = new Action(pageEditor.Id, rw.Id, rw.GetType().Name, XmlTags.StartPointTag,
                            rw.StartPoint.ToString(), newPt.ToString());
                        rw.StartPoint = newPt;
                        mi.AddAction(act);
                    }
                    else
                    {
                        Point newPt = new Point(rw.StartPoint.X + maxWidth, rw.EndPoint.Y);
                        Action act = new Action(pageEditor.Id, rw.Id, rw.GetType().Name, XmlTags.EndPointTag,
                            rw.EndPoint.ToString(), newPt.ToString());
                        rw.EndPoint = newPt;
                        mi.AddAction(act);
                    }
                }

                xOffset += maxWidth + padding;//最大宽度+间距！！！
            }

            List<ILinkableLine> linkedLines = pageEditor.GetLinkedLines(selectedWidgets);

            //刷新挂接的直线的位置
            pageEditor.RefreshLinkedLines(mi, linkedLines);
            manager.RegisterModifingItem(mi);
            manager.RefreshAutoNumberStrings();
            return string.Empty;
        }

        #endregion
    }
}
